package com.atguigu.tingshu.order.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.RabbitConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AssertUtil;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;
    //需要我们手动创建对象
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderDerateMapper orderDerateMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /*
        订单类型：
            1、专辑订单
                购买整张专辑：使用专辑声音的数量*单个声音的价格计算
                            需要考虑折扣
                明细 展示专辑信息
            2、声音订单
                购买多个声音：
                明细  每个声音一个
            3、vip订单
                 购买vip即可
                 明细 vip方案 明细
     */
    @Override
    public OrderInfoVo trade(TradeVo tradeVo) {
        //判断购买类型
        String itemType = tradeVo.getItemType();
        Long itemId = tradeVo.getItemId();
        BigDecimal originalAmount = new BigDecimal("0");
        BigDecimal orderAmount = new BigDecimal("0");;
        BigDecimal derateAmount = new BigDecimal("0");;
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        if(SystemConstant.ORDER_ITEM_TYPE_VIP.equals(itemType)){
            //vip订单
            //1、查询要购买的vip方案信息: service-user vip.....
            // itemId标识 要购买的vip方案id
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.findById(itemId);
            AssertUtil.resultAssert(vipServiceConfigResult, ResultCodeEnum.DATA_ERROR);
            //vip购买方案
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            //2、根据vip方案生成订单数据
            //订单原价
            originalAmount = vipServiceConfig.getPrice();
            //订单价格
            orderAmount = vipServiceConfig.getDiscountPrice();
            //折扣价格
            derateAmount = originalAmount.subtract(orderAmount);
            //订单明细列表:
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(vipServiceConfig.getId());
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemPrice(originalAmount);
//            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVoList.add(orderDetailVo);
            //订单减免明细列表：
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
            orderDerateVo.setDerateAmount(derateAmount);//减免金额
            orderDerateVo.setRemarks(vipServiceConfig.getIntro());//备注
            orderDerateVoList.add(orderDerateVo);
        }
        else if(SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(itemType)){
            //专辑订单
            //1、查询用户是否已购买专辑   itemId表示要购买的专辑id
            Result<Boolean> buyAlbumResult = userInfoFeignClient.isBuyAlbum(itemId,
                    AuthContextHolder.getHeaderToken());
            AssertUtil.resultAssert(buyAlbumResult,ResultCodeEnum.DATA_ERROR);
            if(buyAlbumResult.getData()){
                throw new GuiguException(ResultCodeEnum.ALBUM_IS_BUY_ERROR);
            }
            //2、查询专辑详情：
            //如果专辑vip有折扣：查询用户信息，判断用户身份 是不是vip
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.findAlbumInfo(itemId);
            AssertUtil.resultAssert(albumInfoResult,ResultCodeEnum.DATA_ERROR);
            AlbumInfo albumInfo = albumInfoResult.getData();
            //2.1 如果专辑vip有折扣 判断用户是不是vip
            BigDecimal discount = albumInfo.getDiscount();//普通折扣
            BigDecimal vipDiscount = albumInfo.getVipDiscount();//vip折扣
            BigDecimal finalDiscount = new BigDecimal("0");//最终的折扣
            if(vipDiscount.compareTo(new BigDecimal("-1"))>0 ){
                //2.2 有vip折扣： 查询用户信息 判断是不是vip
                Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(AuthContextHolder.getUserId());
                AssertUtil.resultAssert(userInfoVoResult,ResultCodeEnum.DATA_ERROR);
                UserInfoVo userInfoVo = userInfoVoResult.getData();
                if(userInfoVo.getIsVip().equals(1) && userInfoVo.getVipExpireTime().after(new Date())){
                    //- 用户是vip
                    //vip折扣
                    if(discount.compareTo(new BigDecimal("-1"))==0){
                        finalDiscount = vipDiscount;  //没有普通折扣 使用vip折扣
                    }else{
                        finalDiscount = vipDiscount.compareTo(discount)<=0?vipDiscount:discount;//如果有普通折扣 选择两者折扣值小的
                    }
                }else{
                    //- 用户不是vip
                    finalDiscount = discount;//普通折扣
                }
            }else{
                finalDiscount = discount;//普通折扣
            }
            //3、组装数据
            originalAmount = albumInfo.getPrice();//订单原价
            // 减免金额：  计算折扣后的价格，使用原价-折扣后的价格
            if(finalDiscount.compareTo(new BigDecimal("-1"))!=0){
                //有折扣
                orderAmount = originalAmount   //折扣价
                        .multiply(finalDiscount.divide(new BigDecimal("10")));
                derateAmount = originalAmount.subtract(orderAmount);//优惠金额
            }else{
                //没有折扣
                orderAmount = originalAmount;
                derateAmount = new BigDecimal("0");
            }

            //订单明细列表:
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(albumInfo.getId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemPrice(originalAmount);
//            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVoList.add(orderDetailVo);
            //订单减免明细列表：
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
            orderDerateVo.setDerateAmount(derateAmount);//减免金额
            orderDerateVo.setRemarks("购买专辑");//备注
            orderDerateVoList.add(orderDerateVo);


        }else{
            //声音订单
            //1、判断购买声音的数量不能小于0
            if(tradeVo.getTrackCount()<0){
                throw new GuiguException(ResultCodeEnum.DATA_ERROR);
            }
            //2、判断声音用户是否已经购买过、专辑是否购买过、专辑是不是vip免费
            //查询要购买的声音列表： 使用一个声音id开始 往后查询TrackCount个！
            Result<List<TrackInfo>> trackInfosResult = trackInfoFeignClient.findTrackInfoList(itemId, tradeVo.getTrackCount());
            AssertUtil.resultAssert(trackInfosResult , ResultCodeEnum.DATA_ERROR);
            List<TrackInfo> trackInfos = trackInfosResult.getData();
            if(CollectionUtils.isEmpty(trackInfos)){
                throw new GuiguException(ResultCodeEnum.DATA_ERROR);
            }
            //根据专辑id查询专辑信息: 专辑包含了 声音价格 付费方式..
            Long albumId = trackInfos.get(0).getAlbumId();
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.findAlbumInfo(albumId);
            AssertUtil.resultAssert(albumInfoResult , ResultCodeEnum.DATA_ERROR);
            AlbumInfo albumInfo = albumInfoResult.getData();
            if(albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)){
                throw new GuiguException(ResultCodeEnum.DATA_ERROR);//专辑免费无需购买
            }
            //查询用户信息
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(AuthContextHolder.getUserId());
            AssertUtil.resultAssert(userInfoVoResult , ResultCodeEnum.DATA_ERROR);
            UserInfoVo userInfoVo = userInfoVoResult.getData();

            if( albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_VIPFREE)
                    && userInfoVo.getIsVip().equals(1) && userInfoVo.getVipExpireTime().after(new Date())){
                throw new GuiguException(ResultCodeEnum.DATA_ERROR);//专辑vip免费无需购买
            }
            //3、生成orderInfoVo数据：
            //vip折扣 和 普通折扣
            BigDecimal discount = albumInfo.getDiscount();//普通折扣
            BigDecimal vipDiscount = albumInfo.getVipDiscount();//vip折扣
            BigDecimal finalDiscount = new BigDecimal("0");//最终的折扣
            if(vipDiscount.compareTo(new BigDecimal("-1"))>0 ){
                //2.2 有vip折扣： 查询用户信息 判断是不是vip
                if(userInfoVo.getIsVip().equals(1) && userInfoVo.getVipExpireTime().after(new Date())){
                    //- 用户是vip
                    //vip折扣
                    if(discount.compareTo(new BigDecimal("-1"))==0){
                        finalDiscount = vipDiscount;  //没有普通折扣 使用vip折扣
                    }else{
                        finalDiscount = vipDiscount.compareTo(discount)<=0?vipDiscount:discount;//如果有普通折扣 选择两者折扣值小的
                    }
                }else{
                    //- 用户不是vip
                    finalDiscount = discount;//普通折扣
                }
            }else{
                finalDiscount = discount;//普通折扣
            }

            //使用折扣计算金额：
            BigDecimal count = new BigDecimal(trackInfos.size());
            originalAmount = albumInfo.getPrice().multiply(count);//订单原价
            // 减免金额：  计算折扣后的价格，使用原价-折扣后的价格
            if(finalDiscount.compareTo(new BigDecimal("-1"))!=0){
                //有折扣
                //订单金额：
                orderAmount = originalAmount   //折扣价
                        .multiply(finalDiscount.divide(new BigDecimal("10")));
                derateAmount = originalAmount.subtract(orderAmount);//优惠金额
            }else{
                //没有折扣
                orderAmount = originalAmount;
                derateAmount = new BigDecimal("0");
            }
            //组装数据：
            //订单明细列表:
            BigDecimal finalDiscount1 = finalDiscount;
            trackInfos.forEach(trackInfo -> {

                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemPrice(albumInfo.getPrice());//原价
//            orderDetailVo.setItemPrice(orderAmount);
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVoList.add(orderDetailVo);

                //订单减免明细列表：
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_ITEM_TYPE_TRACK);
                //计算减免金额
                BigDecimal price = albumInfo.getPrice();
                BigDecimal finalDerateAmount = price.subtract(price.multiply(finalDiscount1
                        .divide(new BigDecimal("10"))));
                orderDerateVo.setDerateAmount(finalDerateAmount);//减免金额
                orderDerateVo.setRemarks("购买声音");//备注
                orderDerateVoList.add(orderDerateVo);
            });



        }


        //对象转换器: 可以将一个类型的对象转为另一个类型(底层：将对象转为json字符串，然后将json字符串转为另一个类型的对象)
        //orderInfoVo => {id:xx,xx:xxx} => Map()

        //为了保证 提交订单的幂等性：缓存交易编号
        String tradeNo = IdUtil.getSnowflakeNextIdStr();
        redisTemplate.opsForValue().set(RedisConstant.TRADE_NO_KEY+AuthContextHolder.getUserId(),
                tradeNo , 500000 + 60000, TimeUnit.MILLISECONDS);


        //最后：要创建一个OrderInfoVo对象返回
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);//支付方式:默认使用wx
        orderInfoVo.setItemType(tradeVo.getItemType()); //购买产品的类型
        orderInfoVo.setOriginalAmount(originalAmount);//订单原价
        orderInfoVo.setDerateAmount(derateAmount);//订单减免金额
        orderInfoVo.setOrderAmount(orderAmount);//订单金额(订单原价 - 订单减免金额)
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);//订单明细列表
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);//订单减免明细列表
        orderInfoVo.setTimestamp(System.currentTimeMillis());//时间戳
        orderInfoVo.setSign(SignHelper
                .getSign(objectMapper.convertValue(orderInfoVo, Map.class)
            )
        );//签名：防止数据被篡改 保证数据安全

        return orderInfoVo;
    }
    @GlobalTransactional //开启全局事务
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String submitOrder(OrderInfoVo orderInfoVo) {
        //1、验证签名
        /*
            签名校验原理：
                - 1、生成签名： 订单确认页数据加载时  手动根据orderInfoVo的属性值生成签名设置到orderInfoVo中
                - 2、校验签名： 再次使用接收到的orderInfoVo生成签名字符串  和 orderInfoVo携带的签名进行比较(比较成功签名正确)
                        为了保证 确认订单时 校验签名因为 支付方式改变校验失败，订单确认页业务中 设置了一个默认的 微信支付值

         */
        Map map = objectMapper.convertValue(orderInfoVo, Map.class);
        map.put("payWay" , SystemConstant.ORDER_PAY_WAY_WEIXIN);
        SignHelper.checkSign(map);//校验失败抛出异常： 参数错误-签名校验失败 或者 订单数据过期
        //2、幂等性
        // 订单确认时 保存的tradeNo
        // 提交订单时 获取上一步缓存的tradeNo 和 当前的tradeNo比较，比较成功删除redis缓存，表示可以执行
//        String tradeNo = (String) redisTemplate.opsForValue().get(RedisConstant.TRADE_NO_KEY + AuthContextHolder.getUserId());
//        if(StringUtils.isEmpty(tradeNo) || !tradeNo.equals(orderInfoVo.getTradeNo())){
//            throw new GuiguException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);//订单重复提交
//        }
//        redisTemplate.delete(RedisConstant.TRADE_NO_KEY + AuthContextHolder.getUserId());
        //以上的操作需要具有原子性： LUA脚本   借助了redis的单线程(接收到的命令或者LUA脚本 执行完成后才会执行下一个命令或者LUA脚本)
        // 可以保证 redis下一个要执行的命令或者LUA脚本 操作的数据 一定是上一个操作结束后的结果
        String checkLua = "if (redis.call('get' , KEYS[1]) == ARGV[1] )  then " +
                " return redis.call('del' , KEYS[1]) else return 0 end";// 返回1 表示比较+删除tradeNo成功   0表示失败
        Boolean flag = (Boolean) redisTemplate.execute(new DefaultRedisScript(checkLua, Boolean.class),
                Arrays.asList(RedisConstant.TRADE_NO_KEY + AuthContextHolder.getUserId()),
                orderInfoVo.getTradeNo()
        );
        if(!flag){
            //tradeNo不存在 或者比较失败  删除失败
            throw new GuiguException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
        }
        //数据校验： 为什么没有校验参数？ 第一步校验签名时，根据参数列表+密钥 生成签名字符串


        //3、判断支付方式：
        if(orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_WAY_ACCOUNT)){
            //3.1 余额支付:账户余额足够 直接交易成功，处理支付成功的业务 保存交易记录..
            //1、校验余额 并 扣除余额   & 保存账户余额流水
            AccountLockVo accountLockVo = new AccountLockVo();
            accountLockVo.setUserId(AuthContextHolder.getUserId());
            accountLockVo.setAmount(orderInfoVo.getOrderAmount());
            accountLockVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
            accountLockVo.setOrderNo(orderInfoVo.getTradeNo());
            Result<Boolean> checkAndDeductionResult = userAccountFeignClient.checkAndDeduction(accountLockVo);
            AssertUtil.resultAssert(checkAndDeductionResult,ResultCodeEnum.ACCOUNT_LESS);
//            checkAndDeductionResult.getData();
            //2、保存订单
            this.saveOrder(orderInfoVo);

//            int i = 1/0;

            //3、余额扣除成功：保存交易记录(用户判断是否购买过产品的凭证)
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setUserId(AuthContextHolder.getUserId());
            userPaidRecordVo.setOrderNo(orderInfoVo.getTradeNo());
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            List<Long> itemIds = orderInfoVo.getOrderDetailVoList()
                    .stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIds);
            Result savePaidRecordResult = userInfoFeignClient.savePaidRecords(userPaidRecordVo);
            AssertUtil.resultAssert(savePaidRecordResult,ResultCodeEnum.DATA_ERROR);
        }else{
            //3.2 在线支付 三方支付： 需要到三方支付的页面中 再次确认 输入密码才可以成功  成功后才可以将订单改为支付成功的状态+ 保存交易记录
            //不需要保存交易记录 不需要扣除账户余额...
            //生成订单保存：订单状态为待支付
            this.saveOrder(orderInfoVo);
        }
        //保存订单后 返回订单编号
        return orderInfoVo.getTradeNo();
    }

    @Override
    public OrderInfo getOrderInfoByOrderNo(String orderNo) {
        //查询订单
        OrderInfo orderInfo = this.getOne(Wrappers.lambdaQuery(OrderInfo.class)
                .eq(OrderInfo::getOrderNo, orderNo)
//                .eq(OrderInfo::getUserId, AuthContextHolder.getUserId())
        )
                ;
        //查询订单明细
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(Wrappers.lambdaQuery(OrderDetail.class)
                .eq(OrderDetail::getOrderId, orderInfo.getId()));
        //查询订单折扣列表
        List<OrderDerate> orderDerates = orderDerateMapper.selectList(Wrappers.lambdaQuery(OrderDerate.class)
                .eq(OrderDerate::getOrderId, orderInfo.getId()));

        orderInfo.setOrderDetailList(orderDetails);
        orderInfo.setOrderDerateList(orderDerates);
        //设置支付方式名称
        orderInfo.setPayWayName(getPayWayName(orderInfo.getPayWay()));
        return orderInfo;
    }
    //确保当前项目已经整合了seata：引入依赖、添加seata配置、数据库中创建undolog日志表、使用事务注解
    //添加本地事务
    @Override
    public Page<OrderInfo> findUserPage(Long pageNum, Long pageSize) {
        Page<OrderInfo> page = orderInfoMapper.selectUserPage(new Page<>(pageNum,pageSize) ,
                AuthContextHolder.getUserId());
        //处理order pay_way_name
        return page;
    }

    @Override
    public Map<Long, Integer> getOrderSaleStates(String date) {
        /*
            List<Map<String,Object>> list;
               查询的专辑销量有多条数据，每一条数据对应一个map
               [
                {albumId:1 , saleNum:2},
                {albumId:2 , saleNum:1},
                {albumId:3 , saleNum:3}
               ]


         */
        Map<Long, Integer> stateMap = new HashMap<>();
        List<Map<String, Object>> list = orderInfoMapper.selectOrderSaleStates(date);
        if(CollectionUtils.isEmpty(list)){
            return null;
        }
        list.forEach(map->{
            stateMap.put(Long.parseLong(map.get("albumId").toString()) ,
                    Integer.parseInt(map.get("saleNum").toString()));
        });
        return stateMap;
    }

    private String getPayWayName(String payWay){
        String paywayName = "";
        switch (payWay){
            case SystemConstant.ORDER_PAY_WAY_WEIXIN:
                paywayName = "微信支付";
                break;
            case SystemConstant.ORDER_PAY_WAY_ACCOUNT:
                paywayName = "账户余额支付";
                break;
            case SystemConstant.ORDER_PAY_WAY_ALIPAY:
                paywayName = "支付宝支付";
                break;
        }
        return paywayName;
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveOrder(OrderInfoVo orderInfoVo) {
        //1、保存订单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo , orderInfo);
        orderInfo.setUserId(AuthContextHolder.getUserId());
        //使用tradeno当作 订单编号（也可以重新生成一个）
        orderInfo.setOrderNo(orderInfoVo.getTradeNo());
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        //支付状态： 如果是余额支付 订单状态为支付成功状态 ， 三方支付：待支付状态 等待回调更新
        String orderStatus = orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_WAY_ACCOUNT)?
                SystemConstant.ORDER_STATUS_PAID:SystemConstant.ORDER_STATUS_UNPAID;
        orderInfo.setOrderStatus(orderStatus);
        orderInfo.setOrderStatusName("待支付");
        orderInfoMapper.insert(orderInfo);
//        orderInfo.s
        //2、保存订单明细
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if(!CollectionUtils.isEmpty(orderDetailVoList)){
            orderDetailVoList.forEach(orderDetailVo -> {
                OrderDetail orderDetail = new OrderDetail();
                // 属性拷贝时 属性名和类型必须一样 否则拷贝失败！！！
                BeanUtils.copyProperties(orderDetailVo , orderDetail);
                //绑定订单id
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailMapper.insert(orderDetail);
            });
        }
        //3、保存订单减免列表
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if(!CollectionUtils.isEmpty(orderDerateVoList)){
            orderDerateVoList.forEach(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                // 属性拷贝时 属性名和类型必须一样 否则拷贝失败！！！
                BeanUtils.copyProperties(orderDerateVo , orderDerate);
                //绑定订单id
                orderDerate.setOrderId(orderInfo.getId());
                orderDerateMapper.insert(orderDerate);
            });
        }
        //4、判断支付类型：如果是余额支付 订单状态为支付成功状态
        //三方支付： 如果订单超时未支付 关闭订单:  通过rabbitmq延迟队列实现
        if(!orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_WAY_ACCOUNT)){
            //发送mq消息！！！！  延迟关单
            rabbitTemplate.convertAndSend(RabbitConstant.ORDER_EXCHANGE,
                        RabbitConstant.ORDER_TTL_RK ,
                        orderInfoVo.getTradeNo()
                    );
        }

    }
}
